using System;
using System.Collections.Generic;
using System.Text;

using System.Data;
using System.IO;
using System.CodeDom.Compiler;
using System.CodeDom;
using Microsoft.CSharp;
using System.Data.SqlClient;
using System.Reflection;
using System.Diagnostics;
using ESBSimpleSamples.ServiceClient.Generator.WSDL;

namespace ESBSimpleSamples.ServiceClient.Generator.Scripts
{
    /// <summary>
    ///
    /// </summary>
    public abstract class CodeDomScript : ScriptBase
    {

        #region Private instance fields

        private CodeTypeDeclaration _declaration;
        private CSharpCodeProvider _codeProvider;
        private List<string> _imports;

        #endregion

        #region Private instance properties

        private CSharpCodeProvider CodeProvider
        {
            get
            {
                if (this._codeProvider == null)
                {
                    this._codeProvider = new CSharpCodeProvider();
                }
                return this._codeProvider;
            }
        }

        protected CodeTypeDeclaration Declaration
        {
            get
            {
                if (this._declaration == null)
                {
                    SetupDeclaration();
                }
                return _declaration;
            }
        }

        protected virtual void SetupDeclaration()
        {
            _declaration = new CodeTypeDeclaration(this.ClassName);
            _declaration.TypeAttributes = TypeAttributes.Public;
            _declaration.IsPartial = true;
        }

        protected virtual string ClassName
        {
            get { return this.GetParameterValue("className"); }
            set { this.SetParameterValue("className", value); }
        }

        protected virtual string Namespace
        {
            get { return this.GetParameterValue("namespace"); }
            set { this.SetParameterValue("namespace", value); }
        }

        private List<string> Imports
        {
            get
            {
                if (this._imports == null)
                {
                    this._imports = new List<string>();
                    this.AddImport("System");
                    this.AddImport("System.Collections.Generic");
                    this.AddImport("System.Text");
                }
                return this._imports;
            }
        }

        protected void AddImport(string importNamespace)
        {
            if (!this.Imports.Contains(importNamespace))
            {
                this.Imports.Add(importNamespace);
            }
        }

        #endregion

        #region Private instance methods

        protected virtual void BuildClass()
        {
            this.AddConstructor();
            this.AddLocalFields();
            this.AddProperties();
            this.AddMethods();
            this.AddStructs();
        }

        protected abstract void AddConstructor();

        protected abstract void AddLocalFields();

        protected abstract void AddProperties();

        protected abstract void AddMethods();

        protected abstract void AddStructs();

        protected void AddMember(CodeTypeMember member)
        {
            this.Declaration.Members.Add(member);
        }

        #endregion

        #region Public instance methods

        public override string Language
        {
            get { return "cs"; }
        }

        protected void OutputClass()
        {
            //reset and build the class declaration:
            this.SetupDeclaration();
            this.BuildClass();

            CodeNamespace nameSpace = new CodeNamespace(this.Namespace);
            nameSpace.Types.Add(this.Declaration);
            this.Imports.Sort(); 
            foreach (string import in this.Imports)
            {
                nameSpace.Imports.Add(new CodeNamespaceImport(import));
            }

            using (StringWriter writer = new StringWriter())
            {
                IndentedTextWriter indentedWriter = new IndentedTextWriter(writer);
                CodeGeneratorOptions options = new CodeGeneratorOptions();
                options.BracingStyle = "C";

                CodeCompileUnit compileUnit = new CodeCompileUnit();
                compileUnit.Namespaces.Add(nameSpace);

                this.CodeProvider.GenerateCodeFromCompileUnit(compileUnit, indentedWriter, options);
                indentedWriter.Flush();
                this.Output.Write(writer.GetStringBuilder().ToString());
            }

            this.Output.Close();

        }

        #endregion

        #region Private structs

        protected struct Attributes
        {
            public const MemberAttributes PrivateStatic = MemberAttributes.Private | MemberAttributes.Static;
            public const MemberAttributes PublicStatic = MemberAttributes.Public | MemberAttributes.Static;
            public const MemberAttributes PublicOverride = MemberAttributes.Public | MemberAttributes.Override;
            public const MemberAttributes ProtectedOverride = MemberAttributes.Family | MemberAttributes.Override;
        }

        #endregion
    }
}